#!/bin/bash
# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

set -x

SCRIPT_PATH="$(dirname "$0")"
EXAMPLE_NAME=iotsdk-example-bluetooth-hci-bridge


#----- Set up the environment

if [[ -z "${ARMLMD_LICENSE_FILE}" ]];
then
    echo "No Arm license found. Please export ARMLMD_LICENSE_FILE"
    exit 1
fi

# Make sure $VHT_PATH is set
[[ -z "${VHT_PATH}" ]] && export VHT_PATH="@PLATFORM_VHT@"
# Make sure $LD_LIBRARY_PATH is set
[[ ! $LD_LIBRARY_PATH =~ .*"/opt/VHT".* ]] && export LD_LIBRARY_PATH="/opt/VHT:"${LD_LIBRARY_PATH}
# Make sure $USER is set because it is needed by babblesim to cleanup after a run
[[ -z "${USER}" ]] && export USER=$(whoami)


# If dbus is not started yet, do start it along the bluetooth
if [[ -n "$(service dbus status | grep "not running")" ]];
then
    service dbus start
    bluetoothd &
    WAS_DBUS_ALREADY_RUNNING=0
else
    WAS_DBUS_ALREADY_RUNNING=1
fi

# Sleep a bit to give bluez the time it might need to startup.
timeout=5
while [[ -n "$(service bluetooth status | grep "not running")" && ${timeout} -gt 0 ]]
do
    sleep 1
    timeout=$(( $timeout - 1 ))
done
if (( timeout <= 0 ));
then
    echo "bluetooth service failed to start"
    exit 1
fi

if [[ "$EUID" -ne 0 ]]
then
    echo "Several commands require to be run as root. You might be prompted to log in."
fi

# If ran as root (like in a container), the various calls to sudo may fail
# Thus, we alias it to only actually call sudo when not being root
sudo ()
{
    if [[ $EUID = 0 ]]
    then
        "$@"
    else
        command sudo "$@"
    fi
}

NIMBLE_PID=""
BTATTACH_REQUESTER_PID=""
BTATTACH_BRIDGE_PID=""
BRIDGE_PID=""


function cleanup_and_exit () {
    # kill all the programs we started
    [[ -n ${NIMBLE_PID} ]] && kill -7 ${NIMBLE_PID}
    [[ -n ${BTATTACH_REQUESTER_PID} ]] && kill -7 ${BTATTACH_REQUESTER_PID}
    [[ -n ${BTATTACH_BRIDGE_PID} ]] && kill -7 ${BTATTACH_BRIDGE_PID}
    if [[ -n ${BRIDGE_PID} ]];
    then
        # Kill the childs processes first
        sudo kill -7 $(pgrep -P ${BRIDGE_PID})
        sudo kill -7 ${BRIDGE_PID}
    fi
    echo ""
    stop_bsim.sh

    # Only kill dbus is we were the one starting it. Killing it also kill blueZ
    if [[ ${WAS_DBUS_ALREADY_RUNNING} -eq 0 ]];
    then
        service dbus stop
    fi

    echo ""
    if [[ ${1} -eq 0 ]];
    then
        echo "Test successful"
    else
        echo "Test failure"
    fi

    # Set the return code for pass/fail check of the test suite. 0 = pass
    exit ${1}
}


#----- Run the test


echo ""

# Run babblesim in the background. Parse and output the two UART to stdout
tty_raw=$(${SCRIPT_PATH}/start_and_parse_babblesim.exp ${SCRIPT_PATH})
babblesim_return_code=$?
tty1=$(echo ${tty_raw} | cut -d ' ' -f 1)
tty2=$(echo ${tty_raw} | cut -d ' ' -f 2)

echo "tty1 : ${tty1}; tty2 : ${tty2}"
if [[ ${babblesim_return_code} -ne 0 || -z ${tty1} || -z ${tty2} ]];
then
    cleanup_and_exit 2
fi



# Attach one of the tty to blueZ as a bluetooth controller
device_id_raw=$(${SCRIPT_PATH}/start_and_parse_btattach.exp ${tty1})
btattach_return_code=$?
BTATTACH_BRIDGE_PID=$(echo ${device_id_raw} | cut -d ' ' -f 1)
device_bridge_id=$(echo ${device_id_raw} | cut -d ' ' -f 4)
echo "device : ${device_bridge_id}"
echo "btattach pid : ${BTATTACH_BRIDGE_PID}"

if [[ ${btattach_return_code} -ne 0 || -z ${device_bridge_id} || ${BTATTACH_BRIDGE_PID} -eq ${device_bridge_id} ]];
then
    cleanup_and_exit 3
fi

# Wait some time for the bluetooth to init.
timeout=5
while [[ -z "$(hciconfig | grep -A2 "hci${device_bridge_id}" | grep "UP RUNNING")" && ${timeout} -gt 0 ]]
do
    sleep 1
    timeout=$(( $timeout - 1 ))
done

if [[ ${timeout} -le 0 ]]
then
    cleanup_and_exit 3
fi



# Attach the second tty to blueZ as a bluetooth controller
device_id_raw=$(${SCRIPT_PATH}/start_and_parse_btattach.exp ${tty2})
btattach_return_code=$?
BTATTACH_REQUESTER_PID=$(echo ${device_id_raw} | cut -d ' ' -f 1)
device_requester_id=$(echo ${device_id_raw} | cut -d ' ' -f 4)
echo "device : ${device_requester_id}"
echo "btattach pid : ${BTATTACH_REQUESTER_PID}"

if [[ ${btattach_return_code} -ne 0 || -z ${device_requester_id} || ${BTATTACH_REQUESTER_PID} -eq ${device_requester_id} ]];
then
    cleanup_and_exit 4
fi

# Wait some time for the bluetooth to init.
timeout=5
while [[ -z "$(hciconfig | grep -A2 "hci${device_requester_id}" | grep "UP RUNNING")" && ${timeout} -gt 0 ]]
do
    sleep 1
    timeout=$(( $timeout - 1 ))
done

if [[ ${timeout} -le 0 ]];
then
    cleanup_and_exit 4
fi


# Start the bridge that will receive the HCI from the FVP and relay it to blueZ
BRIDGE_PID=$(sudo ${SCRIPT_PATH}/start_and_parse_bridge.exp ${device_bridge_id} $(which hci-ip-bridge))
bridge_return_code=$?
echo "bridge pid : ${BRIDGE_PID}"

if [[ ${bridge_return_code} -ne 0 || -z ${BRIDGE_PID} ]];
then
    cleanup_and_exit 5
fi



# Start and log both the python script and the VHT as they need to run together.
${VHT_PATH} -C mps3_board.visualisation.disable-visualisation=1 -C mps3_board.smsc_91c111.enabled=1 -C mps3_board.hostbridge.userNetworking=1 -C cpu0.semihosting-enable=1 -C mps3_board.telnetterminal0.start_telnet=0 -C mps3_board.uart0.out_file="-"  -C mps3_board.uart0.unbuffered_output=1 --stat  -C mps3_board.DISABLE_GATING=1 -a __build/${EXAMPLE_NAME}.elf 2>&1 >nimble_output.txt &
NIMBLE_PID=$!
python3 ${SCRIPT_PATH}/test_requester.py ${device_requester_id} 2>&1 >python_output.txt

# Compare the logs to previously verified logs. If they match, then the test pass.
# If the test fail, we keep the logs and print them
python3 ${SCRIPT_PATH}/compare_log.py nimble_output.txt ${SCRIPT_PATH}/expected_nimble_output.txt
nimble_match_return_code=$?
python3 ${SCRIPT_PATH}/compare_log.py python_output.txt ${SCRIPT_PATH}/expected_python_output.txt
python_match_return_code=$?

if [[ nimble_match_return_code -eq 0 && python_match_return_code -eq 0 ]]
then
    rm nimble_output.txt
    rm python_output.txt
else
    if [[ nimble_match_return_code -ne 0 ]]
    then
        echo "NimBLE's output does not match the expected output"
        echo "NimBLE's output:"
        cat nimble_output.txt
        echo "expected output:"
        cat ${SCRIPT_PATH}/expected_nimble_output.txt
    fi
    if [[ python_match_return_code -ne 0 ]]
    then
        echo "Python's output does not match the expected output"
        echo "Python's output:"
        cat python_output.txt
        echo "expected output:"
        cat ${SCRIPT_PATH}/expected_python_output.txt
    fi
    cleanup_and_exit 6
fi

#----- We reached the end : test sucessful

cleanup_and_exit 0
